using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Web;
using System.Web.UI.WebControls;

namespace Framework
{
	public static class WebUtil
    {
        // *********************************************************************************
        // HTTP Context/Server/Items
        // *********************************************************************************

        #region Context
        /// <summary>
        /// Gets the current HTTP context.
        /// </summary>
        /// <value>The HTTP context.</value>
        public static HttpContext Context
        {
            get { return HttpContext.Current; }
        } 
        #endregion

        #region Server
        /// <summary>
        /// Gets the HTTP server.
        /// </summary>
        /// <value>The HTTP server.</value>
        public static HttpServerUtility Server
        {
            get { return HttpContext.Current.Server; }
        } 
	    #endregion

        #region ServerVariable
	    /// <summary>
	    /// Gets a Request.ServerVariable value, return String.Empty if not found.
	    /// </summary>
	    /// <param name="name">The name.</param>
	    /// <returns></returns>
	    public static string ServerVariable(string name)
	    {
            return ServerVariable(Context.Request, name, String.Empty);
	    }

	    /// <summary>
        /// Gets a Request.ServerVariable value, return defaultValue if not found.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static string ServerVariable(string name, string defaultValue)
        {
            return ServerVariable(Context.Request, name, defaultValue);

        }

        /// <summary>
        /// Gets a Request.ServerVariable value.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="name">The name.</param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string ServerVariable(HttpRequest req, string name, string defaultValue)
        {
            return StrUtil.DefaultValue(req.ServerVariables[name], defaultValue);
        }
        #endregion

        #region Items
        /// <summary>
        /// Gets the current HTTP context.
        /// </summary>
        /// <value>The HTTP context.</value>
        public static IDictionary Items
        {
            get { return HttpContext.Current.Items; }
        }
        #endregion

        // *********************************************************************************
        // URL Rewrites/Redirects
        // *********************************************************************************

        #region Redirect301
        //http://www.agilewebtechnologies.com/blog/post/2007/11/Redirects-Using-404-Error-Handling-in-ASPNET-20-on-Shared-Hosting-(Part-3).aspx

        /// <summary>
        /// 301 Redirect to the specified URL, this SEO friendly.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="endResponse">if set to <c>true</c> [end response].</param>
        public static void Redirect301(Uri url, bool endResponse)
        {
            var context = HttpContext.Current;

            if (context == null) return;

            context.Response.Status = "301 Moved Permanently";
            context.Response.AddHeader("Location", url.AbsoluteUri);
            
            if (endResponse)
            {
                context.Response.End();
            }
        }  
        #endregion

        // *********************************************************************************
        // Encode/Decode query strings
        // *********************************************************************************

		#region UrlEncode
		public static string UrlEncode(string text)
		{
			return System.Web.HttpUtility.UrlEncode(text);
		}
		#endregion

		#region UrlDecode
		public static string UrlDecode(string text)
		{
			return System.Web.HttpUtility.UrlDecode(text);
		}
		#endregion

        #region StripUnSafeCharacters
        public static string StripUnSafeCharacters(string text)
        {
            return Is.EmptyString(text) ? string.Empty : StrUtil.Replace(text, "'", "", FrameworkConstant.DEFAULT_COMPARISON_IGNORECASE);
        }
	    #endregion

        // *********************************************************************************
        // Request / Query Parameters
        // *********************************************************************************

        #region Req (Get Request Values as String, Bool, Int)
        /// <summary>
        /// Retreive request value, if the request value is null or empty string then return <var>String.Empty</var>.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static string Req(HttpRequest req, string key)
        {
            return Req(false, req, key, string.Empty);
        }
        /// <summary>
        /// Retreive request value, if the request value is null or empty string then return <var>String.Empty</var>.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static string Req(HttpRequest req, string key, string defaultValue)
        {
            return Req(false, req, key, defaultValue);
        }

        /// <summary>
        /// Retreive request value, if the request value is null or empty string then return <var>String.Empty</var>.
        /// </summary>
        /// <param name="isUrlEncode">if set to <c>true</c> [is URL encode].</param>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static string Req(bool isUrlEncode, HttpRequest req, string key)
        {
            return Req(isUrlEncode, req, key, string.Empty);
        }

        /// <summary>
        /// Retreive request value, if the request value is null or empty string then return<var>defaultValue</var>.
        /// </summary>
        /// <param name="isUrlEncode">if set to <c>true</c> [is URL encode].</param>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static string Req(bool isUrlEncode, HttpRequest req, string key, string defaultValue)
        {
            var reqValue = req[key];

            //Encoded URL do not get Decoded correctly by the ASP.NET framework
            //if( reqValue != null)
            //     reqValue = reqValue.Replace(' ', '+');

            if (isUrlEncode)
            {
                reqValue = Server.UrlEncode(reqValue);
            }

            return StrUtil.DefaultValue(reqValue, defaultValue);
        }

        /// <summary>
        /// Retreive request value as date time.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static DateTime ReqAsDateTime(HttpRequest req, string key)
        {
            return DateUtil.ToDateTime(req[key]);
        }

        /// <summary>
        /// Retreive request value as int.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static int ReqAsInt(HttpRequest req, string key)
        {
            return NumUtil.ParseInt(req[key], 0);
        }

        /// <summary>
        /// Retreive request value as int, if the request value is null or does not parse as an int then return<var>defaultValue</var>.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static int ReqAsInt(HttpRequest req, string key, int defaultValue)
        {
            return NumUtil.ParseInt(req[key], defaultValue);
        }

        /// <summary>
        /// Retreive request value as decimal.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static decimal ReqAsDecimal(HttpRequest req, string key)
        {
            return NumUtil.ParseDecimal(req[key], 0);
        }

        /// <summary>
        /// Retreive request value as decimal, if the request value is null or does not parse as an decimal then return<var>defaultValue</var>.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static decimal ReqAsDecimal(HttpRequest req, string key, decimal defaultValue)
        {
            return NumUtil.ParseDecimal(req[key], defaultValue);
        }

        /// <summary>
        /// Retreive request value as bool.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static bool ReqAsBool(HttpRequest req, string key)
        {
            return Is.True(req[key]);
        }

        /// <summary>
        /// Retreive request value as bool, if the request value is null or does not parse as a bool then return<var>defaultValue</var>.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">if set to <c>true</c> [default value].</param>
        /// <returns></returns>
        public static bool ReqAsBool(HttpRequest req, string key, bool defaultValue)
        {
            var value = req[key];

            return value == null ? defaultValue : Is.True(req[key]);
        }
        #endregion

        #region CacheResponse
        /// <summary>
        /// Caches response for the specified duration, used for a browser cache.
        /// </summary>
        /// <param name="duration">The duration.</param>
        public static void CacheResponse(TimeSpan duration)
        {
            HttpCachePolicy cache = HttpContext.Current.Response.Cache;

            FieldInfo maxAgeField = cache.GetType().GetField("_maxAge", BindingFlags.Instance | BindingFlags.NonPublic);
            maxAgeField.SetValue(cache, duration);

            cache.SetCacheability(HttpCacheability.Public);
            cache.SetExpires(DateTime.Now.Add(duration));
            cache.SetMaxAge(duration);
            cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
        } 
        #endregion

        // *********************************************************************************
        // Web Controls
        // *********************************************************************************

        #region ResetControls
        public static void ResetControls(params WebControl[] controls)
        {
            foreach (WebControl ctrl in controls)
            {
                if (ctrl is TextBox)
                {
                    ((TextBox)ctrl).Text = String.Empty;
                }
                else if (ctrl is DropDownList)
                {
                    ((DropDownList)ctrl).SelectedIndex = 0;
                }
                else if (ctrl is Label)
                {
                    ((Label)ctrl).Text = String.Empty;
                }
            }
        }
        #endregion

        #region EnableControls
        public static void EnableControls(bool isEnabled, params WebControl[] controls)
        {
            foreach (WebControl ctrl in controls)
            {
                ctrl.Enabled = isEnabled;
            }
        }
        #endregion

        // *********************************************************************************
        // URL's
        // *********************************************************************************

        #region MapPath
        /// <summary>
        /// Returns the physical file path that corresponds to the specified virtual path on the web server.
        /// </summary>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        public static string MapPath(Uri uri)
        {
            return MapPath(uri.LocalPath);
        }

        /// <summary>
        /// Returns the physical file path that corresponds to the specified virtual path on the web server.
        /// </summary>
        /// <value>Physical file path</value>
        public static string MapPath(string path)
        {
            return HttpContext.Current == null ? path : HttpContext.Current.Server.MapPath(path);
        }
	    #endregion

        #region MapAbsolutePath
        /// <summary>
        /// Returns the absolute file path for the web server (This is not a physical file location).
        /// </summary>
        /// <value>Absolute file path</value>
        public static string MapAbsolutePath(string path)
        {
            return VirtualPathUtility.ToAbsolute(path);
        }
        #endregion

        #region ServerPort
        public static string ServerPort()
        {
            var result = ServerVariable("SERVER_PORT", "80");

            return result.Equals("80") || result.Equals("443") ? String.Empty : ":" + result;
        }
        #endregion

        #region ServerProtocol
        public static string ServerProtocol()
        {
            var result = ServerVariable("SERVER_PORT_SECURE", "0");

            return result.Equals("0") ? "http://" : "https://";
        }
        #endregion

        #region ServerHostName

	    /// <summary>
	    /// Construct a server host name.
	    /// </summary>
	    /// <returns></returns>
	    public static string ServerHostName()
	    {
            return ServerHostName(ServerVariable("SERVER_NAME"));
	    }

	    /// <summary>
        /// Construct a server host name
        /// </summary>
        /// <param name="serverName">Name of the server e.g. (www.blah.com).</param>
        /// <returns></returns>
        public static string ServerHostName(string serverName)
        {
	        return ServerProtocol() + serverName + ServerPort();
        }
        #endregion

        #region GetOriginalUrlFromRequest
        /// <summary>
        /// Gets the original URL (before rewrite) from request.
        /// </summary>
        /// <returns></returns>
        public static string GetOriginalUrlFromRequest(HttpRequest request)
        {
            return request.RawUrl;
        }
        #endregion

        #region ParseQueryString
        public static NameValueCollection ParseQueryString(Uri uri)
        {
            return HttpUtility.ParseQueryString(uri.Query);
        }
        #endregion

        // *********************************************************************************
        // Insert Comment
        // *********************************************************************************

        #region ValidateUrlPrefix
        /// <summary>
        /// Simple validator for URL's prefix.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static bool ValidateUrlPrefix(string url)
        {
            return Is.NotEmptyString(url) &&
                   (
                       StrUtil.StartsWith(url, "http://") ||
                       StrUtil.StartsWith(url, "https://") ||
                       StrUtil.StartsWith(url, "ftp://")
                   );
        }
        #endregion

        #region ReadUrlToFile
		/// <summary>
		/// Request the contents from a URL and write to file.
		/// </summary>
		/// <param name="url">URL to read from</param>
		/// <param name="fileName">File to write to</param>
		public static void ReadUrlToFile(string url, string fileName)
		{
			var wc = new WebClient();

			wc.DownloadFile(url, fileName);
		}
		#endregion

        #region ReadUrlToBase64String
        /// <summary>
        /// Request the contents from a URL and return as a base64 string. Uses GET method by default.
        /// </summary>
        /// <param name="url">URL to read from</param>
        public static string ReadUrlToBase64String(string url)
        {
            var wc = new WebClient();

            var data = wc.DownloadData(url);

            return Convert.ToBase64String(data);
        }
        #endregion

		#region ReadUrlToString
		/// <summary>
		/// Request the contents from a URL and return as a string. Uses GET method by default.
		/// </summary>
		/// <param name="url">URL to read from</param>
		public static string ReadUrlToString(string url)
		{
			var wc = new WebClient();

			return wc.DownloadString(url);
		}


        /// <summary>
        /// Request the contents from a URL and return as a string.
        /// </summary>
        /// <param name="url">URL to read from</param>
        /// <param name="contentType">Type of the content.</param>
        /// <returns></returns>
		public static string ReadUrlToString(string url, string contentType)
		{
			var wc = new WebClient();

			wc.Headers.Add("Content-Type", contentType);

			return wc.DownloadString(url);
		}

        /// <summary>
        /// Reads the URL to string.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="method">The method.</param>
        /// <param name="postParams">The post params.</param>
        /// <returns></returns>
        public static string ReadUrlToString(string url, string method, string postParams)
        {
            var wc = new WebClient();

            // set the user agent to IE6
            wc.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)");

            try
            {
                if (Is.EqualString(method, "POST"))
                {
                    // Eg "field1=value1&amp;field2=value2"
                    var bret = wc.UploadData(url, "POST", Encoding.UTF8.GetBytes(postParams));

                    return Encoding.UTF8.GetString(bret);
                }

                // actually execute the GET request
                return wc.DownloadString(url);
            }
            catch (WebException we)
            {
                // WebException.Status holds useful information
                LogUtil.ErrorF("Failed to read URL to string.\n{0}\n{1}", we, we.Message, we.Status);
                throw;
            }
            catch (Exception ex)
            {
                // other errors
                LogUtil.Error("Failed to read URL to string.", ex);
                throw;
            }
        }

        /// <summary>
        /// Reads the URL to string.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="method">The method.</param>
        /// <param name="postParams">The post params.</param>
        /// <param name="userName">Name of the user.</param>
        /// <param name="password">The password.</param>
        /// <param name="domain">The domain.</param>
        /// <returns></returns>
        public static string ReadUrlToString(string url, string method, string postParams, string userName, string password, string domain)
        {
            var wc = new WebClient();

            // set the user agent to IE6
            wc.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)");

            AssignCredentials(wc, userName, password, domain);

            try
            {
                if (Is.EqualString(method, "POST"))
                {
                    // Eg "field1=value1&amp;field2=value2"
                    var bret = wc.UploadData(url, "POST", Encoding.UTF8.GetBytes(postParams));

                    return Encoding.UTF8.GetString(bret);
                }

                // actually execute the GET request
                return wc.DownloadString(url);
            }
            catch (WebException we)
            {
                // WebException.Status holds useful information
                LogUtil.ErrorF("Failed to read URL to string.\n{0}\n{1}", we, we.Message, we.Status);
                throw;
            }
            catch (Exception ex)
            {
                // other errors
                LogUtil.Error("Failed to read URL to string.", ex);
                throw;
            }
        }
        #endregion

		#region ReadWebResponseToString
		public static string ReadWebResponseToString(WebResponse response)
		{
			return new StreamReader(response.GetResponseStream()).ReadToEnd();
		}
		#endregion

        #region DownloadFileFromStringAsBytes
        /// <summary>
        /// Download a data string as a byte[] to a file on the clients system
        /// </summary>
        public static void DownloadFileFromStringAsBytes(HttpResponse response, string fileName, string data)
        {
            var resultBytes = Encoding.UTF8.GetBytes(data);

            var fi = new FileInfo(fileName);

            response.Clear();
            response.ContentType = "application/octet-stream";
            response.AddHeader("Content-Disposition", "attachment; filename=" + fileName.Replace(' ', '_'));
            response.AddHeader("Content-Length", resultBytes.Length.ToString());
            response.BinaryWrite(resultBytes);
            response.End();
        }
        #endregion

        #region DownloadFile
		/// <summary>
		/// Download File
		/// </summary>
		/// <param name="response">Response object</param>
		/// <param name="filename">Filename key</param>
		/// <return>
		/// Download Succeded Y/N
		/// </return>
		public static bool DownloadFile(HttpResponse response, string fileName)
		{
			return DownloadFile(response, fileName, true);
        }

		/// <summary>
		/// Download File
		/// </summary>
		/// <param name="response">Response object</param>
		/// <param name="filename">Filename key</param>
		/// <param name="forceDownload">Force the browser to display the open/save dialog on download</param>
		/// <return>
		/// Download Succeded Y/N
		/// </return>
		public static bool DownloadFile(HttpResponse response, string fileName, bool forceDownload)
		{
			FileInfo fi = new FileInfo(fileName);

			bool result = false;

			if (!fi.Exists)
			{
				return result;
			}

			try
			{
				response.ClearContent();
				response.ContentType = GetContentType(fi.Extension);
				response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(fi.FullName));
				response.AddHeader("Content-Length", fi.Length.ToString());
				response.WriteFile(fi.FullName);
				response.Flush();
			}
            //catch (Exception ex)
            //{
            //    //Logger.Error("Download file error", ex);
            //}
			finally
			{
				response.End();
			}
			return result;
		}
		#endregion

		#region GetContentType
		public static string GetContentType(string extension)
		{
			switch (extension.ToLower())
			{
				case ".htm":
				case ".html":
					return "text/HTML";

				case ".txt":
					return "text/plain";

				case ".doc":
				case ".rtf":
					return "application/msword";

                case ".xls":
                    return "application/vnd.ms-excel";

                case ".pdf":
					return "application/pdf";

				case ".zip":
					return "application/zip";
			}
            return "text/plain";
        }
		#endregion

		#region DownloadLargeFile
		/// <summary>
		/// Download File
		/// </summary>
		/// <param name="response">Response object</param>
		/// <param name="filename">Filename key</param>
		/// <param name="defaultValue">Value to return on null or empty request value</param>
		public static void DownloadLargeFile(HttpResponse response, string fileName)
		{
			/*
					 // The secret file (path) to download.
					 string filepath  = @"C:\Downloads\LargeDocument.doc";

					 // The file name used to save the file to the client's system..
					 string  filename  = System.IO.Path.GetFileName( filepath );

					 System.IO.Stream stream = null;
					 try
					 {
						// Open the file into a stream.
						stream = new System.IO.FileStream( filepath, System.IO.FileMode.Open, 
						   System.IO.FileAccess.Read, System.IO.FileShare.Read );

						// Total bytes to read:
						long bytesToRead = stream.Length;

						Response.Contentreturn "application/octet-stream";
						Response.AddHeader( "Content-Disposition", "attachment; filename=" + 
						   filename );

						// Read the bytes from the stream in small portions.
						while ( bytesToRead > 0 )
						{
						   // Make sure the client is still connected.
						   if ( Response.IsClientConnected ) 
						   {
							  // Read the data into the buffer and write into the 
							  // output stream.

							  byte[] buffer = new Byte[10000];
							  int length = stream.Read( buffer, 0, 10000 );
							  Response.OutputStream.Write(buffer, 0, length);
							  Response.Flush();

							  // We have already read some bytes.. need to read 
							  // only the remaining.
							  bytesToRead = bytesToRead - length;
						   }
						   else
						   {
							  // Get out of the loop, if user is not connected anymore..
							  bytesToRead = -1;
						   }
						}
					 }
					 catch
					 {
						// An error occurred.. do whatever you want in this situation !
					 }
					 finally
					 {
						if ( stream != null ) 
						{
						   stream.Close();
						}
					 }
			*/
		}
		#endregion

        #region GetFullHost
        public static string GetFullHost(Uri uri)
        {
            return string.Format("{0}://{1}/", uri.Scheme, uri.Host);
        } 
        #endregion

		#region GetUri
		public static Uri GetUri(string url)
		{
			return GetUri("http://www.somehost.com/", url);
		}

		public static Uri GetUri(string host, string url)
		{
			return new Uri(new Uri(host), url);
		}
		#endregion

		#region CompressCss
		public static string CompressCss(string css)
		{
			// Based on http://andrewu.co.uk/clj/compress_css/

			string result = css;

			// Kill Comments
			Regex re = new Regex(@"\/\*[^\*]*\*\/");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith().Evaluator);

			// Kill Tabs
			re = new Regex(@"\t");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith().Evaluator);

			// Kill space after colons
			re = new Regex(@":\s+");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith(":").Evaluator);

			// Kill mulitple white space characters
			re = new Regex(@" +");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith(" ").Evaluator);

			// Multiple whitespace lines
			re = new Regex(@"^\s*$", RegexOptions.Multiline);

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith().Evaluator);

			// Kill any spaces, newlines before and after Brace {
			re = new Regex(@"\s*[{]");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith("{").Evaluator);

			re = new Regex(@"[{]\s*");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith("{").Evaluator);

			// Kill any spaces, newlines before and after Brace }
			re = new Regex(@"\s*[}]");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith("}").Evaluator);

			re = new Regex(@"[}]\s*");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith("}\n").Evaluator);

			// Kill any spaces, newlines before and after SemiColon ;
			re = new Regex(@"\s*[;]");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith(";").Evaluator);

			re = new Regex(@"[;]\s*");

			result = re.Replace(result, RegExUtil.CreateMatchEvaluatorReplaceWith(";").Evaluator);

			return result;
		}
		#endregion

		#region PageTypeToUrl, PageIdToUrl, PageUrlToId
		public static string PageTypeToUrl(Type type)
		{
			return PageIdToUrl(type.FullName);
		}

		public static string PageIdToUrl(string pageId)
		{
			return "/" + pageId.Replace(".", "/") + ".aspx";
		}

		public static string PageUrlToId(string url)
		{
			string result = GetUri(url).LocalPath.Replace("/", ".").ToLower();

			if (result.EndsWith(".aspx"))
			{
				result = result.Substring(0, result.Length - 5);
			}

			if (result.StartsWith(".") && result.Length > 1)
			{
				result = result.Substring(1);
			}

			return result;
		}
		#endregion

		#region AppendQueryParameter
		public static string AppendQueryParameter(string url, string name, string value)
		{
			Uri uri = GetUri(url);

			StringBuilder result = new StringBuilder(uri.AbsoluteUri);

			result.Append(Is.EmptyString(uri.Query) ? "?" : "&");
			result.Append(name);
			result.Append("=");
			result.Append(UrlEncode(value));

			return result.ToString();
		}
		#endregion

        #region AssignCredentials
        private static void AssignCredentials(WebClient wc, string userName, string password, string domain)
        {
            if (Is.NotEmptyString(userName))
            {
                wc.Credentials = Is.EmptyString(domain)
                                     ? new NetworkCredential(userName, password)
                                     : new NetworkCredential(userName, password, domain);
            }
        } 
        #endregion

        // *********************************************************************************
        // Tracking
        // *********************************************************************************

        #region TrackingPixel
        private static readonly byte[] Image1x1TrackingPixel = Convert.FromBase64String("R0lGODlhAQABAIAAANvf7wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");

        /// <summary>
        /// Sends a 1x1 trackings pixel down the response stream.
        /// </summary>
        /// <param name="response">The response.</param>
        public static void TrackingPixel(HttpResponse response)
        {
            response.ContentType = "image/gif";
            response.AppendHeader("Content-Length", Image1x1TrackingPixel.Length.ToString());
            response.Cache.SetLastModified(DateTime.Now);
            response.Cache.SetCacheability(HttpCacheability.Public);
            response.BinaryWrite(Image1x1TrackingPixel);
        }
        #endregion
    }
}
